import { flipOptions, corners, isTouch, A90 } from "./utils/constant";
import {
  point2D,
  divAtt,
  findPos,
  gradient,
  deg,
  rotate,
  translate,
  trigger,
  bezier,
  autoprefix,
} from "./utils";
import TurnJsError from "./utils/TurnJsError";

const $ = window.$;

export const flipMethods = {
  // Constructor

  init: function (opts) {
    this.data({
      f: {
        disabled: false,
        hover: false,
        effect: this.hasClass("hard") ? "hard" : "sheet",
      },
    });

    this.flip("options", opts);

    flipMethods._addPageWrapper.call(this);

    return this;
  },

  setData: function (d) {
    var data = this.data();

    data.f = $.extend(data.f, d);

    return this;
  },

  options: function (opts) {
    var data = this.data().f;

    if (opts) {
      flipMethods.setData.call(this, {
        opts: $.extend({}, data.opts || flipOptions, opts),
      });
      return this;
    } else return data.opts;
  },

  z: function (z) {
    var data = this.data().f;

    data.opts["z-index"] = z;

    if (data.fwrapper)
      data.fwrapper.css({
        zIndex: z || parseInt(data.parent.css("z-index"), 10) || 0,
      });

    return this;
  },

  _cAllowed: function () {
    var data = this.data().f,
      page = data.opts.page,
      turnData = data.opts.turn.data(),
      odd = page % 2;

    if (data.effect == "hard") {
      return turnData.direction == "ltr"
        ? [odd ? "r" : "l"]
        : [odd ? "l" : "r"];
    } else {
      if (turnData.display == "single") {
        if (page == 1)
          return turnData.direction == "ltr"
            ? corners["forward"]
            : corners["backward"];
        else if (page == turnData.totalPages)
          return turnData.direction == "ltr"
            ? corners["backward"]
            : corners["forward"];
        else return corners["all"];
      } else {
        return turnData.direction == "ltr"
          ? corners[odd ? "forward" : "backward"]
          : corners[odd ? "backward" : "forward"];
      }
    }
  },

  _cornerActivated: function (p) {
    var data = this.data().f,
      width = this.width(),
      height = this.height(),
      point = { x: p.x, y: p.y, corner: "" },
      csz = data.opts.cornerSize;

    if (point.x <= 0 || point.y <= 0 || point.x >= width || point.y >= height)
      return false;

    var allowedCorners = flipMethods._cAllowed.call(this);

    switch (data.effect) {
      case "hard":
        if (point.x > width - csz) point.corner = "r";
        else if (point.x < csz) point.corner = "l";
        else return false;

        break;

      case "sheet":
        if (point.y < csz) point.corner += "t";
        else if (point.y >= height - csz) point.corner += "b";
        else return false;

        if (point.x <= csz) point.corner += "l";
        else if (point.x >= width - csz) point.corner += "r";
        else return false;

        break;
    }

    return !point.corner || $.inArray(point.corner, allowedCorners) == -1
      ? false
      : point;
  },

  _isIArea: function (e) {
    var pos = this.data().f.parent.offset();

    e = isTouch && e.originalEvent ? e.originalEvent.touches[0] : e;

    return flipMethods._cornerActivated.call(this, {
      x: e.pageX - pos.left,
      y: e.pageY - pos.top,
    });
  },

  _c: function (corner, opts) {
    opts = opts || 0;

    switch (corner) {
      case "tl":
        return point2D(opts, opts);
      case "tr":
        return point2D(this.width() - opts, opts);
      case "bl":
        return point2D(opts, this.height() - opts);
      case "br":
        return point2D(this.width() - opts, this.height() - opts);
      case "l":
        return point2D(opts, 0);
      case "r":
        return point2D(this.width() - opts, 0);
    }
  },

  _c2: function (corner) {
    switch (corner) {
      case "tl":
        return point2D(this.width() * 2, 0);
      case "tr":
        return point2D(-this.width(), 0);
      case "bl":
        return point2D(this.width() * 2, this.height());
      case "br":
        return point2D(-this.width(), this.height());
      case "l":
        return point2D(this.width() * 2, 0);
      case "r":
        return point2D(-this.width(), 0);
    }
  },

  _foldingPage: function () {
    var data = this.data().f;

    if (!data) return;

    var opts = data.opts;

    if (opts.turn) {
      data = opts.turn.data();
      if (data.display == "single")
        return opts.next > 1 || opts.page > 1 ? data.pageObjs[0] : null;
      else return data.pageObjs[opts.next];
    }
  },

  _backGradient: function () {
    var data = this.data().f,
      turnData = data.opts.turn.data(),
      gradient =
        turnData.opts.gradients &&
        (turnData.display == "single" ||
          (data.opts.page != 2 && data.opts.page != turnData.totalPages - 1));

    if (gradient && !data.bshadow)
      data.bshadow = $("<div/>", divAtt(0, 0, 1))
        .css({ position: "", width: this.width(), height: this.height() })
        .appendTo(data.parent);

    return gradient;
  },

  type: function () {
    return this.data().f.effect;
  },

  resize: function (full) {
    var data = this.data().f,
      turnData = data.opts.turn.data(),
      width = this.width(),
      height = this.height();

    switch (data.effect) {
      case "hard":
        if (full) {
          data.wrapper.css({ width: width, height: height });
          data.fpage.css({ width: width, height: height });
          if (turnData.opts.gradients) {
            data.ashadow.css({ width: width, height: height });
            data.bshadow.css({ width: width, height: height });
          }
        }

        break;
      case "sheet":
        if (full) {
          var size = Math.round(
            Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
          );

          data.wrapper.css({ width: size, height: size });
          data.fwrapper
            .css({ width: size, height: size })
            .children(":first-child")
            .css({ width: width, height: height });

          data.fpage.css({ width: width, height: height });

          if (turnData.opts.gradients)
            data.ashadow.css({ width: width, height: height });

          if (flipMethods._backGradient.call(this))
            data.bshadow.css({ width: width, height: height });
        }

        if (data.parent.is(":visible")) {
          var offset = findPos(data.parent[0]);

          data.fwrapper.css({ top: offset.top, left: offset.left });

          //if (data.opts.turn) {
          offset = findPos(data.opts.turn[0]);
          data.fparent.css({ top: -offset.top, left: -offset.left });
          //}
        }

        this.flip("z", data.opts["z-index"]);

        break;
    }
  },

  // Prepares the page by adding a general wrapper and another objects

  _addPageWrapper: function () {
    var data = this.data().f,
      turnData = data.opts.turn.data(),
      parent = this.parent();

    data.parent = parent;

    if (!data.wrapper)
      switch (data.effect) {
        case "hard":
          var cssProperties = autoprefix({
            "transform-style": "preserve-3d",
            "backface-visibility": "hidden",
          });

          data.wrapper = $("<div/>", divAtt(0, 0, 2))
            .css(cssProperties)
            .appendTo(parent)
            .prepend(this);

          data.fpage = $("<div/>", divAtt(0, 0, 1))
            .css(cssProperties)
            .appendTo(parent);

          if (turnData.opts.gradients) {
            data.ashadow = $("<div/>", divAtt(0, 0, 0)).hide().appendTo(parent);

            data.bshadow = $("<div/>", divAtt(0, 0, 0));
          }

          break;
        case "sheet":
          data.fparent = data.opts.turn.data().fparent;

          if (!data.fparent) {
            var fparent = $("<div/>", {
              css: { "pointer-events": "none" },
            }).hide();
            fparent.data().flips = 0;
            fparent
              .css(divAtt(0, 0, "auto", "visible").css)
              .appendTo(data.opts.turn);

            data.opts.turn.data().fparent = fparent;
            data.fparent = fparent;
          }

          this.css({
            position: "absolute",
            top: 0,
            left: 0,
            bottom: "auto",
            right: "auto",
          });

          data.wrapper = $("<div/>", divAtt(0, 0, this.css("z-index")))
            .appendTo(parent)
            .prepend(this);

          data.fwrapper = $(
            "<div/>",
            divAtt(parent.offset().top, parent.offset().left)
          )
            .hide()
            .appendTo(data.fparent);

          data.fpage = $("<div/>", divAtt(0, 0, 0, "visible"))
            .css({ cursor: "default" })
            .appendTo(data.fwrapper);

          if (turnData.opts.gradients)
            data.ashadow = $("<div/>", divAtt(0, 0, 1)).appendTo(data.fpage);

          flipMethods.setData.call(this, data);

          break;
      }

    // Set size
    flipMethods.resize.call(this, true);
  },

  // Takes a 2P point from the screen and applies the transformation

  _fold: function (point) {
    var data = this.data().f,
      turnData = data.opts.turn.data(),
      o = flipMethods._c.call(this, point.corner),
      width = this.width(),
      height = this.height();

    switch (data.effect) {
      case "hard":
        if (point.corner == "l")
          point.x = Math.min(Math.max(point.x, 0), width * 2);
        else point.x = Math.max(Math.min(point.x, width), -width);

        var leftPos,
          shadow,
          gradientX,
          fpageOrigin,
          parentOrigin,
          totalPages = turnData.totalPages,
          zIndex = data.opts["z-index"] || totalPages,
          parentCss = { overflow: "visible" },
          relX = o.x ? (o.x - point.x) / width : point.x / width,
          angle = relX * 90,
          half = angle < 90;

        switch (point.corner) {
          case "l":
            fpageOrigin = "0% 50%";
            parentOrigin = "100% 50%";

            if (half) {
              leftPos = 0;
              shadow = data.opts.next - 1 > 0;
              gradientX = 1;
            } else {
              leftPos = "100%";
              shadow = data.opts.page + 1 < totalPages;
              gradientX = 0;
            }

            break;
          case "r":
            fpageOrigin = "100% 50%";
            parentOrigin = "0% 50%";
            angle = -angle;
            width = -width;

            if (half) {
              leftPos = 0;
              shadow = data.opts.next + 1 < totalPages;
              gradientX = 0;
            } else {
              leftPos = "-100%";
              shadow = data.opts.page != 1;
              gradientX = 1;
            }

            break;
        }

        data.wrapper.transform(
          "rotateY(" +
            angle +
            "deg)" +
            "translate3d(0px, 0px, " +
            (this.attr("depth") || 0) +
            "px)",
          parentOrigin
        );

        data.fpage.transform(
          "translateX(" + width + "px) rotateY(" + (180 + angle) + "deg)",
          fpageOrigin
        );

        data.parent.css({
          ...parentCss,
          ...autoprefix({
            "perspective-origin": parentOrigin,
          }),
        });

        if (half) {
          relX = -relX + 1;
          data.wrapper.css({ zIndex: zIndex + 1 });
          data.fpage.css({ zIndex: zIndex });
        } else {
          relX = relX - 1;
          data.wrapper.css({ zIndex: zIndex });
          data.fpage.css({ zIndex: zIndex + 1 });
        }

        if (turnData.opts.gradients) {
          if (shadow)
            data.ashadow
              .css({
                display: "",
                left: leftPos,
                backgroundColor: "rgba(0,0,0," + 0.5 * relX + ")",
              })
              .transform("rotateY(0deg)");
          else data.ashadow.hide();

          data.bshadow.css({ opacity: -relX + 1 });

          if (half) {
            if (data.bshadow.parent()[0] != data.wrapper[0]) {
              data.bshadow.appendTo(data.wrapper);
            }
          } else {
            if (data.bshadow.parent()[0] != data.fpage[0]) {
              data.bshadow.appendTo(data.fpage);
            }
          }
          /*data.bshadow.css({
            backgroundColor: 'rgba(0,0,0,'+(0.1)+')'
          })*/
          gradient(
            data.bshadow,
            point2D(gradientX * 100, 0),
            point2D((-gradientX + 1) * 100, 0),
            [
              [0, "rgba(0,0,0,0.3)"],
              [1, "rgba(0,0,0,0)"],
            ],
            2
          );
        }

        break;
      case "sheet":
        var that = this,
          a = 0,
          alpha = 0,
          px,
          gradientEndPointA,
          gradientEndPointB,
          gradientStartVal,
          gradientSize,
          gradientOpacity,
          shadowVal,
          mv = point2D(0, 0),
          df = point2D(0, 0),
          tr = point2D(0, 0),
          folding = flipMethods._foldingPage.call(this),
          ac = turnData.opts.acceleration,
          h = data.wrapper.height(),
          top = point.corner.substr(0, 1) == "t",
          left = point.corner.substr(1, 1) == "l",
          compute = function () {
            var rel = point2D(0, 0);
            var middle = point2D(0, 0);

            rel.x = o.x ? o.x - point.x : point.x;

            rel.y = o.y ? o.y - point.y : point.y;

            middle.x = left ? width - rel.x / 2 : point.x + rel.x / 2;
            middle.y = rel.y / 2;

            var alpha = A90 - Math.atan2(rel.y, rel.x),
              gamma = alpha - Math.atan2(middle.y, middle.x),
              distance = Math.max(
                0,
                Math.sin(gamma) *
                  Math.sqrt(Math.pow(middle.x, 2) + Math.pow(middle.y, 2))
              );

            a = deg(alpha);

            tr = point2D(
              distance * Math.sin(alpha),
              distance * Math.cos(alpha)
            );

            if (alpha > A90) {
              tr.x = tr.x + Math.abs((tr.y * rel.y) / rel.x);
              tr.y = 0;
              if (Math.round(tr.x * Math.tan(Math.PI - alpha)) < height) {
                point.y = Math.sqrt(Math.pow(height, 2) + 2 * middle.x * rel.x);
                if (top) point.y = height - point.y;
                return compute();
              }
            }

            if (alpha > A90) {
              var beta = Math.PI - alpha,
                dd = h - height / Math.sin(beta);
              mv = point2D(
                Math.round(dd * Math.cos(beta)),
                Math.round(dd * Math.sin(beta))
              );
              if (left) mv.x = -mv.x;
              if (top) mv.y = -mv.y;
            }

            px = Math.round(tr.y / Math.tan(alpha) + tr.x);

            var side = width - px,
              sideX = side * Math.cos(alpha * 2),
              sideY = side * Math.sin(alpha * 2);
            df = point2D(
              Math.round(left ? side - sideX : px + sideX),
              Math.round(top ? sideY : height - sideY)
            );

            // Gradients
            if (turnData.opts.gradients) {
              gradientSize = side * Math.sin(alpha);

              var endingPoint = flipMethods._c2.call(that, point.corner),
                far =
                  Math.sqrt(
                    Math.pow(endingPoint.x - point.x, 2) +
                      Math.pow(endingPoint.y - point.y, 2)
                  ) / width;

              shadowVal = Math.sin(A90 * (far > 1 ? 2 - far : far));

              gradientOpacity = Math.min(far, 1);

              gradientStartVal =
                gradientSize > 100 ? (gradientSize - 100) / gradientSize : 0;

              gradientEndPointA = point2D(
                ((gradientSize * Math.sin(alpha)) / width) * 100,
                ((gradientSize * Math.cos(alpha)) / height) * 100
              );

              if (flipMethods._backGradient.call(that)) {
                gradientEndPointB = point2D(
                  ((gradientSize * 1.2 * Math.sin(alpha)) / width) * 100,
                  ((gradientSize * 1.2 * Math.cos(alpha)) / height) * 100
                );

                if (!left) gradientEndPointB.x = 100 - gradientEndPointB.x;
                if (!top) gradientEndPointB.y = 100 - gradientEndPointB.y;
              }
            }

            tr.x = Math.round(tr.x);
            tr.y = Math.round(tr.y);

            return true;
          },
          transform = function (tr, c, x, a) {
            var f = ["0", "auto"],
              mvW = ((width - h) * x[0]) / 100,
              mvH = ((height - h) * x[1]) / 100,
              cssA = {
                left: f[c[0]],
                top: f[c[1]],
                right: f[c[2]],
                bottom: f[c[3]],
              },
              cssB = {},
              aliasingFk = a != 90 && a != -90 ? (left ? -1 : 1) : 0,
              origin = x[0] + "% " + x[1] + "%";

            that
              .css(cssA)
              .transform(
                rotate(a) + translate(tr.x + aliasingFk, tr.y, ac),
                origin
              );

            data.fpage
              .css(cssA)
              .transform(
                rotate(a) +
                  translate(
                    tr.x + df.x - mv.x - (width * x[0]) / 100,
                    tr.y + df.y - mv.y - (height * x[1]) / 100,
                    ac
                  ) +
                  rotate((180 / a - 2) * a),
                origin
              );

            data.wrapper.transform(
              translate(-tr.x + mvW - aliasingFk, -tr.y + mvH, ac) + rotate(-a),
              origin
            );

            data.fwrapper.transform(
              translate(-tr.x + mv.x + mvW, -tr.y + mv.y + mvH, ac) +
                rotate(-a),
              origin
            );

            if (turnData.opts.gradients) {
              if (x[0]) gradientEndPointA.x = 100 - gradientEndPointA.x;

              if (x[1]) gradientEndPointA.y = 100 - gradientEndPointA.y;

              cssB["box-shadow"] =
                "0 0 20px rgba(0,0,0," + 0.5 * shadowVal + ")";
              folding.css(cssB);

              gradient(
                data.ashadow,
                point2D(left ? 100 : 0, top ? 0 : 100),
                point2D(gradientEndPointA.x, gradientEndPointA.y),
                [
                  [gradientStartVal, "rgba(0,0,0,0)"],
                  [
                    (1 - gradientStartVal) * 0.8 + gradientStartVal,
                    "rgba(0,0,0," + 0.2 * gradientOpacity + ")",
                  ],
                  [1, "rgba(255,255,255," + 0.2 * gradientOpacity + ")"],
                ],
                3,
                alpha
              );

              if (flipMethods._backGradient.call(that))
                gradient(
                  data.bshadow,
                  point2D(left ? 0 : 100, top ? 0 : 100),
                  point2D(gradientEndPointB.x, gradientEndPointB.y),
                  [
                    [0.6, "rgba(0,0,0,0)"],
                    [0.8, "rgba(0,0,0," + 0.3 * gradientOpacity + ")"],
                    [1, "rgba(0,0,0,0)"],
                  ],
                  3
                );
            }
          };

        switch (point.corner) {
          case "l":
            break;
          case "r":
            break;
          case "tl":
            point.x = Math.max(point.x, 1);
            compute();
            transform(tr, [1, 0, 0, 1], [100, 0], a);
            break;
          case "tr":
            point.x = Math.min(point.x, width - 1);
            compute();
            transform(point2D(-tr.x, tr.y), [0, 0, 0, 1], [0, 0], -a);
            break;
          case "bl":
            point.x = Math.max(point.x, 1);
            compute();
            transform(point2D(tr.x, -tr.y), [1, 1, 0, 0], [100, 100], -a);
            break;
          case "br":
            point.x = Math.min(point.x, width - 1);
            compute();
            transform(point2D(-tr.x, -tr.y), [0, 1, 1, 0], [0, 100], a);
            break;
        }

        break;
    }

    data.point = point;
  },

  _moveFoldingPage: function (move) {
    var data = this.data().f;

    if (!data) return;

    var turn = data.opts.turn,
      turnData = turn.data(),
      place = turnData.pagePlace;

    if (move) {
      var nextPage = data.opts.next;

      if (place[nextPage] != data.opts.page) {
        if (data.folding) flipMethods._moveFoldingPage.call(this, false);

        var folding = flipMethods._foldingPage.call(this);

        folding.appendTo(data.fpage);
        place[nextPage] = data.opts.page;
        data.folding = nextPage;
      }

      turn.turn("update");
    } else {
      if (data.folding) {
        if (turnData.pages[data.folding]) {
          // If we have flip available

          var flipData = turnData.pages[data.folding].data().f;

          turnData.pageObjs[data.folding].appendTo(flipData.wrapper);
        } else if (turnData.pageWrap[data.folding]) {
          // If we have the pageWrapper

          turnData.pageObjs[data.folding].appendTo(
            turnData.pageWrap[data.folding]
          );
        }

        if (data.folding in place) {
          place[data.folding] = data.folding;
        }

        delete data.folding;
      }
    }
  },

  _showFoldedPage: function (c, animate) {
    var folding = flipMethods._foldingPage.call(this),
      dd = this.data(),
      data = dd.f,
      visible = data.visible;

    if (folding) {
      if (!visible || !data.point || data.point.corner != c.corner) {
        var corner =
          data.status == "hover" ||
          data.status == "peel" ||
          data.opts.turn.data().mouseAction
            ? c.corner
            : null;

        visible = false;

        if (trigger("start", this, [data.opts, corner]) == "prevented")
          return false;
      }

      if (animate) {
        var that = this,
          point =
            data.point && data.point.corner == c.corner
              ? data.point
              : flipMethods._c.call(this, c.corner, 1);

        this.animatef({
          from: [point.x, point.y],
          to: [c.x, c.y],
          duration: 500,
          frame: function (v) {
            c.x = Math.round(v[0]);
            c.y = Math.round(v[1]);
            flipMethods._fold.call(that, c);
          },
        });
      } else {
        flipMethods._fold.call(this, c);

        if (dd.effect && !dd.effect.turning) this.animatef(false);
      }

      if (!visible) {
        switch (data.effect) {
          case "hard":
            data.visible = true;
            flipMethods._moveFoldingPage.call(this, true);
            data.fpage.show();
            if (data.opts.shadows) data.bshadow.show();

            break;
          case "sheet":
            data.visible = true;
            data.fparent.show().data().flips++;
            flipMethods._moveFoldingPage.call(this, true);
            data.fwrapper.show();
            if (data.bshadow) data.bshadow.show();

            break;
        }
      }

      return true;
    }

    return false;
  },

  hide: function () {
    var data = this.data().f,
      turnData = data.opts.turn.data(),
      folding = flipMethods._foldingPage.call(this);

    switch (data.effect) {
      case "hard":
        if (turnData.opts.gradients) {
          data.bshadowLoc = 0;
          data.bshadow.remove();
          data.ashadow.hide();
        }

        data.wrapper.transform("");
        data.fpage.hide();

        break;
      case "sheet":
        if (--data.fparent.data().flips === 0) data.fparent.hide();

        this.css({
          left: 0,
          top: 0,
          right: "auto",
          bottom: "auto",
        }).transform("");

        data.wrapper.transform("");

        data.fwrapper.hide();

        if (data.bshadow) data.bshadow.hide();

        folding.transform("");

        break;
    }

    data.visible = false;

    return this;
  },

  hideFoldedPage: function (animate) {
    var data = this.data().f;

    if (!data.point) return;

    var that = this,
      p1 = data.point,
      hide = function () {
        data.point = null;
        data.status = "";
        that.flip("hide");
        that.trigger("end", [data.opts, false]);
      };

    if (animate) {
      var p4 = flipMethods._c.call(this, p1.corner),
        top = p1.corner.substr(0, 1) == "t",
        delta = top
          ? Math.min(0, p1.y - p4.y) / 2
          : Math.max(0, p1.y - p4.y) / 2,
        p2 = point2D(p1.x, p1.y + delta),
        p3 = point2D(p4.x, p4.y - delta);

      this.animatef({
        from: 0,
        to: 1,
        frame: function (v) {
          var np = bezier(p1, p2, p3, p4, v);
          p1.x = np.x;
          p1.y = np.y;
          flipMethods._fold.call(that, p1);
        },
        complete: hide,
        duration: 800,
        hiding: true,
      });
    } else {
      this.animatef(false);
      hide();
    }
  },

  turnPage: function (corner) {
    var that = this,
      data = this.data().f,
      turnData = data.opts.turn.data();

    corner = {
      corner: data.corner
        ? data.corner.corner
        : corner || flipMethods._cAllowed.call(this)[0],
    };

    var p1 =
        data.point ||
        flipMethods._c.call(
          this,
          corner.corner,
          data.opts.turn ? turnData.opts.elevation : 0
        ),
      p4 = flipMethods._c2.call(this, corner.corner);

    this.trigger("flip").animatef({
      from: 0,
      to: 1,
      frame: function (v) {
        var np = bezier(p1, p1, p4, p4, v);
        corner.x = np.x;
        corner.y = np.y;
        flipMethods._showFoldedPage.call(that, corner);
      },
      complete: function () {
        that.trigger("end", [data.opts, true]);
      },
      duration: turnData.opts.duration,
      turning: true,
    });

    data.corner = null;
  },

  moving: function () {
    return "effect" in this.data();
  },

  isTurning: function () {
    return this.flip("moving") && this.data().effect.turning;
  },

  corner: function () {
    return this.data().f.corner;
  },

  _eventStart: function (e) {
    var data = this.data().f,
      turn = data.opts.turn;

    if (
      !data.corner &&
      !data.disabled &&
      !this.flip("isTurning") &&
      data.opts.page == turn.data().pagePlace[data.opts.page]
    ) {
      data.corner = flipMethods._isIArea.call(this, e);

      if (data.corner && flipMethods._foldingPage.call(this)) {
        this.trigger("pressed", [data.point]);
        flipMethods._showFoldedPage.call(this, data.corner);

        return false;
      } else data.corner = null;
    }
  },

  _eventMove: function (e) {
    var data = this.data().f;

    if (!data.disabled) {
      e = isTouch ? e.originalEvent.touches : [e];

      if (data.corner) {
        var pos = data.parent.offset();
        data.corner.x = e[0].pageX - pos.left;
        data.corner.y = e[0].pageY - pos.top;
        flipMethods._showFoldedPage.call(this, data.corner);
      } else if (data.hover && !this.data().effect && this.is(":visible")) {
        var point = flipMethods._isIArea.call(this, e[0]);

        if (point) {
          if (
            (data.effect == "sheet" && point.corner.length == 2) ||
            data.effect == "hard"
          ) {
            data.status = "hover";
            var origin = flipMethods._c.call(
              this,
              point.corner,
              data.opts.cornerSize / 2
            );
            point.x = origin.x;
            point.y = origin.y;
            flipMethods._showFoldedPage.call(this, point, true);
          }
        } else {
          if (data.status == "hover") {
            data.status = "";
            flipMethods.hideFoldedPage.call(this, true);
          }
        }
      }
    }
  },

  _eventEnd: function () {
    var data = this.data().f,
      corner = data.corner;

    if (!data.disabled && corner) {
      if (trigger("released", this, [data.point || corner]) != "prevented") {
        flipMethods.hideFoldedPage.call(this, true);
      }
    }

    data.corner = null;
  },

  disable: function (disable) {
    flipMethods.setData.call(this, { disabled: disable });
    return this;
  },

  hover: function (hover) {
    flipMethods.setData.call(this, { hover: hover });
    return this;
  },

  peel: function (corner, animate) {
    var data = this.data().f;

    if (corner) {
      if ($.inArray(corner, corners.all) == -1)
        throw new TurnJsError("Corner " + corner + " is not permitted");

      if ($.inArray(corner, flipMethods._cAllowed.call(this)) != -1) {
        var point = flipMethods._c.call(this, corner, data.opts.cornerSize / 2);

        data.status = "peel";

        flipMethods._showFoldedPage.call(
          this,
          {
            corner: corner,
            x: point.x,
            y: point.y,
          },
          animate
        );
      }
    } else {
      data.status = "";

      flipMethods.hideFoldedPage.call(this, animate);
    }

    return this;
  },
};
